﻿#pragma once

#ifdef _WIN32
#pragma  comment(lib,"Ws2_32.lib")
#include <WinSock2.h> // WinSock2.h 和 windows.h不可调换顺序
//#include <windows.h> 
#else
#include <sys/uio.h>
#include <endian.h>
#endif // _WIN32

#include <SocketOps.h>
#include <string>
#include <vector>
#include <cassert>

namespace Buffer {
	
	class Buffer {
	public:
		static const size_t KCheapPrepend; // buffer的前KCheapPrepend是拓展字节
		static const size_t KInitialSize;
	public:
		Buffer(size_t initialSize = KInitialSize);

		/// <summary>
		/// 返回buffer的可读字节首地址
		/// </summary>
		/// <returns></returns>
		char* peek();

		/// <summary>
		/// 从fd中读取数据到buffer中
		/// </summary>
		/// <returns>读取的字节数</returns>
		ssize_t readFd(int fd,int* saveError);

		/// <summary>
		/// 丢弃buffer中的len个可读字节
		/// </summary>
		void retrieve(size_t len);

		/// <summary>
		/// 向buffer中添加len个字节
		/// </summary>
		void append(const char* data, int len);

		/// <summary>
		/// 丢弃所有可读字节，并重置读写index
		/// </summary>
		void retrieveAll();

		/// <summary>
		/// 取出buffer的len个字节并转换为std::string
		/// </summary>
		/// <returns></returns>
		std::string retrieveAsString(size_t len);

		/// <summary>
		/// 读取buffer的所有字节，并转换为std::string
		/// </summary>
		std::string retrieveAllAsString();

		void retrieveInt16();
		
		void retrieveInt8();

		void retrieveInt32();
		
		void retrieveInt64();

		void appendInt8(int8_t data);
		
		void appendInt16(int16_t data);
		
		void appendInt32(int32_t data);
		
		void appendInt64(int64_t data);

		char* beginWrite();

		/// <summary>
		/// 交换两个Buffer的数据
		/// </summary>
		void swap(Buffer& other);

		const char* beginWrite() const;

		char* beginRead();
	
		const char* beginRead()const;

		/// <summary>
		/// 更新写index
		/// </summary>
		void hasWritten(int len);

		/// <summary>
		/// 可拓展字节数
		/// </summary>
		size_t prependableBytes();

		/// <summary>
		/// 可读字节数
		/// </summary>
		size_t readableBytes();

		/// <summary>
		/// 可写字节数
		/// </summary>
		size_t writableBytes();

		/// <summary>
		/// 判断是否有len个字节可写，没有则resize buffer，确保有len个字节可写
		/// </summary>
		void ensureWritableBytes(size_t len);

	private:
		/// <summary>
		/// 返回buffer的第一个字节地址
		/// </summary>
		char* begin() {
			return &(*buffer_.begin());
		}

		const char* begin() const {
			return &(*buffer_.begin());
		}

		/// <summary>
		/// 如果buffer中的可写字节>len则移动buffer中的数据到prepend字节后
		/// 否则在writeIndex_后拓展一段长度为len的内存
		/// </summary>
		void makeSpace(size_t len);

	private:
		std::vector<char> buffer_;
		size_t readerIndex_; // 使用index而不是iterator的原因是防止在resize的时候迭代器失效
		size_t writerIndex_;

		static const char kCRLF[];
	};
}